package com.mosai.alignpro.view;

import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;

import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
import com.mosai.alignpro.R;
import com.mosai.alignpro.entity.Angle;
import com.mosai.alignpro.entity.BitmapInfo;
import com.mosai.alignpro.entity.ImageInfo;
import com.mosai.alignpro.entity.Point;
import com.mosai.alignpro.entity.RemoveAngleInfo;
import com.mosai.alignpro.util.DialogUtils;
import com.mosai.alignpro.util.LogUtils;
import com.mosai.alignpro.util.ToastUtils;
import com.mosai.alignpro.util.Utils;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Created by Rays on 2020/3/9.
 */
public class DiagnosisView extends View {

    public static final String TAG = DiagnosisView.class.getSimpleName();

    private Bitmap bitmap;
    private BitmapInfo bitmapInfo;
    private Matrix matrix = new Matrix();
    private Paint linePaint = new Paint();
    private Paint angleTextPaint = new Paint();
    private Paint angleSymbolPaint = new Paint();
    private Paint dashPaint = new Paint();
    private Paint circlePaint = new Paint();
    private Point circlePoint;
    private List<List<Float>> customData = new ArrayList<>();
    private List<List<Float>> data;
    private List<Angle> angles;
    private static final int[] colors = {
            Color.parseColor("#FF41E741"),
            Color.parseColor("#FFEFF72E"),
            Color.parseColor("#FF26D3E5"),
            Color.parseColor("#FF4141EB")
    };
    private static final int[] dashCircleColors = {
            Color.parseColor("#8041E741"),
            Color.parseColor("#80EFF72E"),
            Color.parseColor("#8026D3E5"),
            Color.parseColor("#804141EB")
    };
    private static final int customColor = Color.parseColor("#E72727");
    private static final int customDashCircleColor = Color.parseColor("#80E72727");
    private float angleSymbolSize, angleTextX, angleTextY, angleSymbolX, angleSymbolY;

    private int width, height;
    private float imgWidth, imgHeight;
    private float imgScaleWidth, imgScaleHeight;

    private float cx, cy, startX, startY;
    private float translateX, translateY;
    private float extraTY; // 底部额外偏移量，底部有可点击区域，所以允许移动图片到上面
    private boolean isTranslateYEnd;

    private RemoveAngleInfo removeAngleInfo;
    private Point curPoint;
    private float pointRadius;
    private float movePointRadius;
    private double movePointRadiusPow;
    private float circleRadius;
    private double circleRadiusPow;
    private float dashLength;
    private float removeMargin; // 删除按钮与文字的间距

    private ScaleGestureDetector scaleGestureDetector;
    private float mScale = 1.0f;
    private boolean isScaleEvent = false;
    private boolean isScaleEventEnd = true;
    public static final float MAX_SCALE = 2.0f;
    public static final float MIN_SCALE = 1.0f;
    private float maxScale = MAX_SCALE;

    private boolean isDisableDrawAngle = false; // 是否禁用画角度
    private boolean hasEditPoint; // 是否可编辑
    private boolean isRequestLoad;
    private boolean isLoadFinish;
    private boolean editing;
    private boolean onlyRemoveTemp; // 仅删除当前添加的
    private boolean isDrawCircle; // 是否画圆

    private Drawable removeImg;

    private OnAngleListener onAngleListener;

    private static boolean centerInside = false; // true: 图片缩小在view中居中显示，false: 图片放大填充满view居中显示

    public DiagnosisView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        DisplayMetrics displayMetrics = getResources().getDisplayMetrics();

        pointRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2.5f, displayMetrics);
        linePaint.setAntiAlias(true);
        linePaint.setStrokeWidth(pointRadius);

        dashPaint.setAntiAlias(true);
        dashPaint.setStrokeWidth(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, displayMetrics));
        dashPaint.setPathEffect(new DashPathEffect(new float[]{10, 10, 10, 10}, 0));
        dashPaint.setStyle(Paint.Style.STROKE);

        circlePaint.setAntiAlias(true);
        circlePaint.setStrokeWidth(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1.5f, displayMetrics));
        circlePaint.setColor(customColor);
        circlePaint.setStyle(Paint.Style.STROKE);

        angleTextPaint.setAntiAlias(true);
        angleTextPaint.setColor(Color.GREEN);
        angleTextPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 14, displayMetrics));
        angleTextPaint.setTextAlign(Paint.Align.RIGHT);
        Paint.FontMetrics fontMetrics = angleTextPaint.getFontMetrics();
        angleTextX = -TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 12, displayMetrics);
        angleTextY = -fontMetrics.ascent;

        angleSymbolPaint.setAntiAlias(true);
        angleSymbolPaint.setColor(Color.GREEN);
        angleSymbolPaint.setStrokeWidth(3);
        angleSymbolPaint.setStyle(Paint.Style.STROKE);
        angleSymbolSize = 5;
        angleSymbolX = angleTextX + angleSymbolSize * 2;
        angleSymbolY = angleTextY + fontMetrics.ascent + angleSymbolSize;

        movePointRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 14, displayMetrics);
        circleRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 14, displayMetrics);
        dashLength = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 30, displayMetrics);
        extraTY = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, displayMetrics);
        removeMargin = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, displayMetrics);

        initRemoveImg();

        scaleGestureDetector = new ScaleGestureDetector(context, new ScaleGestureDetector.OnScaleGestureListener() {
            @Override
            public boolean onScale(ScaleGestureDetector detector) {
                float scaleFactor = scaleGestureDetector.getScaleFactor();
                float scale = mScale * scaleFactor;
                if (scale >= maxScale) {
                    mScale = maxScale;
                } else {
                    mScale = Math.max(scale, MIN_SCALE);
                }
                scaleChange();

//                LogUtils.d(TAG, "onScale: "
//                        + " mScale: " + mScale
//                        + " getScaleFactor: " + scaleFactor
//                );
                postInvalidate();
                return true;
            }

            @Override
            public boolean onScaleBegin(ScaleGestureDetector detector) {
                isScaleEvent = true;
                return true;
            }

            @Override
            public void onScaleEnd(ScaleGestureDetector detector) {
                isScaleEvent = false;
            }
        });
    }

    private void initRemoveImg() {
        removeImg = getResources().getDrawable(R.drawable.remove_angle);
        int iconWidth = removeImg.getIntrinsicWidth();
        int iconHeight = removeImg.getIntrinsicHeight();
        removeImg.setBounds(-iconWidth / 2, -iconHeight / 2, iconWidth / 2, iconHeight / 2);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (isRequestLoad && isLoadFinish) {
            initBitmap(bitmap);
            return;
        }
        if (bitmap == null) {
            return;
        }
        if (width != getWidth() || height != getHeight()) {
            initBitmap(bitmap);
            return;
        }

        // 平移画布
        canvas.translate(translateX, translateY);

        // 缩放画布
        canvas.scale(mScale, mScale);

        // 画背景
        canvas.drawBitmap(bitmap, matrix, linePaint);

        if (angles == null || isDisableDrawAngle) {
            return;
        }
        // 画线、画角度
        for (Angle angle : angles) {
            drawLineAndAngle(canvas, angle, 0, true);
            drawLineAndAngle(canvas, angle, 2, true);
        }

        drawCircle(canvas);
    }

    private void drawCircle(Canvas canvas) {
        if (!isDrawCircle) {
            return;
        }
        if (angles.size() == 2) {
            Point point = angles.get(1).getPoints().get(3);
            dashPaint.setColor(point.getColor());
            canvas.drawLine(point.getX() - dashLength, point.getY(), point.getX(), point.getY(), dashPaint);
        }

        if (circlePoint == null) {
            return;
        }
        circlePaint.setStyle(Paint.Style.STROKE);
        canvas.drawCircle(circlePoint.getX(), circlePoint.getY(), circleRadius, circlePaint);
        circlePaint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(circlePoint.getX(), circlePoint.getY(), pointRadius, circlePaint);

        // 画删除按钮
        if (editing && (!onlyRemoveTemp || circlePoint.isTemp())) {
            canvas.save();
            float x = circlePoint.getX() - circleRadius - removeMargin - removeImg.getIntrinsicWidth() / 2.0f;
            float y = circlePoint.getY();
            circlePoint.setRemoveAngleInfo(new RemoveAngleInfo(x, y, removeImg, circlePoint, circlePoint.toString()));
            canvas.translate(x, y);
            removeImg.draw(canvas);
            canvas.restore();
        }

        List<Angle> angles = circlePoint.getAngles();
        if (angles == null || angles.size() != 2) {
            return;
        }
        dashPaint.setColor(customColor);
        for (Angle angle : angles) {
            drawableDashLine(canvas, angle, dashPaint);
        }
    }

    private void drawableDashLine(Canvas canvas, Angle angle, Paint dashPaint) {
        List<Point> points = angle.getPoints();
        if (points.size() != 4) {
            return;
        }
        canvas.drawLine(points.get(0).getX(), points.get(0).getY(), points.get(1).getX(), points.get(1).getY(), dashPaint);
        canvas.drawLine(points.get(2).getX(), points.get(2).getY(), points.get(3).getX(), points.get(3).getY(), dashPaint);
    }

    public void drawLineAndAngle(Canvas canvas, Angle angle, int i, boolean drawDash) {
        Point point1 = angle.getPoints().get(i);
        Point point2 = angle.getPoints().get(i + 1);
        int color = point1.getColor();
        linePaint.setColor(color);
        float startX = point1.getX();
        float startY = point1.getY();
        // 画线
        canvas.drawLine(startX, startY, point2.getX(), point2.getY(), linePaint);
        // 画点
        canvas.drawCircle(point1.getX(), point1.getY(), pointRadius, linePaint);
        canvas.drawCircle(point2.getX(), point2.getY(), pointRadius, linePaint);

        if (i == 2) {
            angleSymbolPaint.setColor(color);
            angleTextPaint.setColor(color);
            // 画角度
            String text = String.valueOf(angle.getAngle());
            float x = startX + angleTextX;
            float y = startY + angleTextY;
            canvas.drawText(text, x, y, angleTextPaint);
            canvas.drawCircle(startX + angleSymbolX, startY + angleSymbolY, angleSymbolSize, angleSymbolPaint);
            canvas.save();

            // 画删除按钮
            if (editing && (!onlyRemoveTemp || angle.isTemp())) {
                Paint.FontMetrics fontMetrics = angleTextPaint.getFontMetrics();
                x = x - angleTextPaint.measureText(text) - removeMargin - removeImg.getIntrinsicWidth() / 2.0f;
                y = (fontMetrics.ascent + fontMetrics.descent) / 2 + y;
                angle.setRemoveAngleInfo(new RemoveAngleInfo(x, y, removeImg, angle, angle.toString()));
                canvas.translate(x, y);
                removeImg.draw(canvas);
                canvas.restore();
            }
        }

        // 画点可点击区域
        if (editing && drawDash) {
            dashPaint.setColor(point1.getDashCircleColor());
            canvas.drawCircle(point1.getX(), point1.getY(), movePointRadius, dashPaint);
            canvas.drawCircle(point2.getX(), point2.getY(), movePointRadius, dashPaint);
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        int action = event.getAction();
        float dx = event.getX() - cx;
        float dy = event.getY() - cy;
        cx = event.getX();
        cy = event.getY();

        int actionMasked = event.getActionMasked();
//        LogUtils.d(TAG, "dispatchTouchEvent: "
//                        + " action: " + action
//                        + " actionMasked: " + actionMasked
//                        + " dx: " + dx
//                        + " dy: " + dy
//                        + " translateX: " + translateX
//                        + " translateY: " + translateY
//                        + " isTranslateEnd: " + isTranslateYEnd
//                        + " curPoint: " + curPoint
//                        + " removeAngleInfo: " + removeAngleInfo
//                        + " isScaleBegin: " + isScaleEvent
//        );

        if (curPoint == null) {
            scaleGestureDetector.onTouchEvent(event);
            if (isScaleEvent) {
                isScaleEventEnd = false;
                requestDisallowInterceptTouchEvent(true);
                return true;
            }
            if (!isScaleEventEnd) {
                isScaleEventEnd = action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL;
                requestDisallowInterceptTouchEvent(true);
                return true;
            }
        }


        if (actionMasked == MotionEvent.ACTION_POINTER_DOWN) {
            curPoint = null;
            removeAngleInfo = null;
            isScaleEventEnd = false;
            requestDisallowInterceptTouchEvent(true);
            return true;
        }

        switch (action) {
            case MotionEvent.ACTION_MOVE:
                if (curPoint != null) {
                    float x = dx / mScale + curPoint.getX();
                    if (x < 0) {
                        x = 0;
                    } else if (x > imgWidth) {
                        x = imgWidth;
                    }
                    curPoint.setX(x);
                    float y = dy / mScale + curPoint.getY();
                    if (y < 0) {
                        y = 0;
                    } else if (y > imgHeight) {
                        y = imgHeight;
                    }
                    curPoint.setY(y);
                    Angle angle = curPoint.getAngle();
                    if (angle != null) {
                        angle.calculateAngle();
                    }
                    onAngleChange();
                } else {
                    float maxTX = getWidth() - imgScaleWidth;
                    if (maxTX >= 0) {
                        translateX = maxTX / 2;
                    } else {
                        float x = translateX + dx;
                        if (x <= maxTX) {
                            translateX = maxTX;
                        } else if (x >= 0) {
                            translateX = 0;
                        } else {
                            translateX = x;
                        }
                    }
                    boolean isVertical = isTranslateYEnd && Math.abs(cy - startY) - Math.abs(cx - startX) > 30;
                    float maxTY = getMaxTY();
                    if (maxTY > 0) {
                        translateY = maxTY / 2;
                    } else {
                        float y = translateY + dy;
                        if (y <= maxTY) {
                            isVertical = isVertical && translateY <= maxTY;
                            translateY = maxTY;
                        } else if (y >= 0) {
                            isVertical = isVertical && translateY == 0;
                            translateY = 0;
                        } else {
                            translateY = y;
                        }
                    }
                    if (isVertical && !hasEditPoint) {
                        requestDisallowInterceptTouchEvent(false);
                        return false;
                    }
                }
                requestDisallowInterceptTouchEvent(true);
                invalidate();
                break;
            case MotionEvent.ACTION_DOWN:
                startX = cx;
                startY = cy;
                isTranslateYEnd = translateY >= 0 || translateY == getMaxTY();
                requestDisallowInterceptTouchEvent(true);
                if (hasMovePoint()) {
                    break;
                }
                removeAngleInfo = hasRemoveAngle();
                break;
            case MotionEvent.ACTION_UP:
                curPoint = null;
                if (removeAngleInfo != null && removeAngleInfo.equals(hasRemoveAngle())) {
                    DialogUtils.showRemoveAngleDialog(getContext(), new DialogUtils.OnClickListener() {
                        @Override
                        protected void onClick(DialogInterface dialog, boolean isPositive) {
                            if (isPositive) {
                                if (removeAngleInfo.getAngle() != null) {
                                    angles.remove(removeAngleInfo.getAngle());
                                } else {
                                    circlePoint = null;
                                }
                                onAngleChange();
                                refreshDraw();
                            }
                            dialog.dismiss();
                            removeAngleInfo = null;
                        }
                    });
                } else {
                    removeAngleInfo = null;
                }
                break;
            case MotionEvent.ACTION_CANCEL:
                curPoint = null;
                removeAngleInfo = null;
                break;
        }
        return true;
    }

    private float getMaxTY() {
        return getHeight() - imgScaleHeight;
//        return getHeight() - imgScaleHeight - extraTY;
    }

    private void requestDisallowInterceptTouchEvent(boolean b) {
        if (!b) {
            getParent().requestDisallowInterceptTouchEvent(false);
        } else if (!hasEditPoint) {
            getParent().requestDisallowInterceptTouchEvent(true);
        }
    }

    private RemoveAngleInfo hasRemoveAngle() {
        if (!hasEditPoint) {
            return null;
        }
        if (angles != null) {
            for (Angle angle : angles) {
                RemoveAngleInfo info = angle.getRemoveAngleInfo();
                if (info != null && calculateDistance(info.getX(), info.getY()) < info.getRadiusPow()) {
                    return info;
                }
            }
        }
        if (circlePoint != null) {
            RemoveAngleInfo info = circlePoint.getRemoveAngleInfo();
            if (info != null && calculateDistance(info.getX(), info.getY()) < info.getRadiusPow()) {
                return info;
            }
        }
        return null;
    }

    private boolean hasMovePoint() {
        if (!hasEditPoint) {
            return false;
        }
        if (angles != null) {
            double minDistance = Double.MAX_VALUE, distance;
            for (Angle angle : angles) {
                for (Point point : angle.getPoints()) {
                    distance = calculateDistance(point);
                    if (distance < movePointRadiusPow && distance < minDistance) {
                        minDistance = distance;
                        curPoint = point;
                    }
                }
            }
        }
        if (curPoint == null && circlePoint != null && calculateDistance(circlePoint) < circleRadiusPow) {
            curPoint = circlePoint;
        }
        return curPoint != null;
    }

    private double calculateDistance(Point point) {
        return calculateDistance(point.getX(), point.getY());
    }

    private double calculateDistance(float px, float py) {
        double x = px * mScale + translateX - cx;
        double y = py * mScale + translateY - cy;
        return Math.pow(x, 2) + Math.pow(y, 2);
    }

    private void initBitmap(Bitmap b) {
        LogUtils.i(TAG, "initBitmap: "
                + " width: " + width
                + " newWidth: " + getWidth()
                + " height: " + height
                + " newHeight: " + getHeight()
        );
        width = getWidth();
        height = getHeight();
        if (width == 0 || height == 0) {
            return;
        }

        if (b == null) {
            InputStream inputStream = getContext().getResources().openRawResource(R.raw.ai);
            bitmapInfo = Utils.getBitmap(inputStream, width, height);
        } else {
            bitmapInfo = Utils.getBitmapInfo(b, width, height);
        }
        if (bitmapInfo == null) {
            return;
        }
        float scale = bitmapInfo.getScale();
        matrix.setScale(scale, scale);
        bitmap = bitmapInfo.getBitmap();
        imgWidth = bitmap.getWidth() * scale;
        imgHeight = bitmap.getHeight() * scale;
        if (centerInside) {
            mScale = 1.0f;
        } else {
            mScale = Math.max(width / imgWidth, height / imgHeight);
        }
        maxScale = Math.max(mScale, MAX_SCALE);
        scaleChange();

        refreshData();
    }

    private void refreshData() {
        angles = new ArrayList<>();
        angles.addAll(pointToAngles(data, false));
        angles.addAll(pointToAngles(customData, true));
        if (customData.size() % 2 == 1) {
            circlePoint = new Point(customData.get(customData.size() - 1), bitmapInfo.getOriginScale(), customColor, customColor, null);
        } else {
            circlePoint = null;
        }
        onAngleChange();
        refreshDraw();
    }

    public List<Angle> pointToAngles(List<List<Float>> data, boolean isCustom) {
        if (data == null || data.isEmpty()) {
            return Collections.emptyList();
        }
        int size = data.size() >> 2;
        if (size == 0) {
            return Collections.emptyList();
        }
        List<Angle> angles = new ArrayList<>(size);
        for (int i = 0; i < size; i++) {
            Angle angle = new Angle();
            for (int j = 0; j < 4; j++) {
                if (isCustom) {
                    angle.setCustom(true);
                    angle.add(new Point(data.get(i * 4 + j), bitmapInfo.getOriginScale(), customColor, customDashCircleColor, angle));
                } else {
                    angle.add(new Point(data.get(i * 4 + j), bitmapInfo.getOriginScale(), colors[i], dashCircleColors[i], angle));
                }
            }
            angle.calculateAngle();
            angles.add(angle);
        }
        return angles;
    }

    private void refreshDraw() {
        isRequestLoad = false;
        postInvalidate();
    }

    private void scaleChange() {
        movePointRadiusPow = Math.pow(movePointRadius * mScale, 2);
        circleRadiusPow = Math.pow(circleRadius * mScale, 2);
//        LogUtils.d(TAG, "scaleChange:"
//                + " mScale: " + mScale
//                + " movePointRadius: " + movePointRadius
//                + " movePointRadiusPow: " + movePointRadiusPow
//        );

        float oldImgScaleWidth = imgScaleWidth;
        float oldImgScaleHeight = imgScaleHeight;
        imgScaleWidth = imgWidth * mScale;
        imgScaleHeight = imgHeight * mScale;
        int width = getWidth();
        int height = getHeight();

        float w = width - imgScaleWidth;
        float h = getMaxTY();
        if (w >= 0 || translateX == 0) {
            translateX = w / 2;
        } else {
            translateX = (width - oldImgScaleWidth) == 0 ? 0 : translateX / (width - oldImgScaleWidth) * w;
        }
        if (h >= 0 || translateY == 0) {
            translateY = h / 2;
        } else {
            translateY = (height - oldImgScaleHeight) == 0 ? 0 : translateY / (height - oldImgScaleHeight) * h;
        }
//        if (translateY > 0) {
//            translateY = 0;
//        } else if (translateY < h) {
//            translateY = h;
//        }
    }

    public void setDisableDrawAngle(boolean disableDrawAngle) {
        isDisableDrawAngle = disableDrawAngle;
    }

    public boolean isHasEditPoint() {
        return hasEditPoint;
    }

    public void setHasEditPoint(boolean hasEditPoint) {
        this.hasEditPoint = hasEditPoint;
        curPoint = null;
        removeAngleInfo = null;
    }

    public void load(ImageInfo imageInfo) {
        onlyRemoveTemp = imageInfo.getDoctorInfo() != null && imageInfo.getDoctorInfo().isAssistant();
        isDrawCircle = !imageInfo.isShowCondition();
        List<List<Float>> data = Utils.getResultList(imageInfo.getCheckResultInfo());
        List<List<Float>> custom = Utils.getResultList(imageInfo.getAddCheckResultInfo());
        load(imageInfo.getUrl(), data, custom);
    }

    public void load(String url, List<List<Float>> data, List<List<Float>> custom) {
        LogUtils.i(TAG, "load"
                + " url: " + url
                + " data: " + data
        );

        bitmap = null;
        bitmapInfo = null;
        isRequestLoad = true;
        isLoadFinish = false;
        this.data = data;
        this.customData = custom;
        this.angles = null;
        if (TextUtils.isEmpty(url)) {
//            post(() -> {
//                isLoadFinish = true;
//                initBitmap(null);
//            });
            postInvalidate();
        } else {
            Glide.with(getContext()).asBitmap().load(url).into(new CustomTarget<Bitmap>() {
                @Override
                public void onResourceReady(@NonNull final Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
                    LogUtils.i(TAG, "onResourceReady"
                            + " width: " + resource.getWidth()
                            + " height: " + resource.getHeight()
                            + " isUiThread: " + Utils.isUiThread()
                    );
                    isLoadFinish = true;
                    bitmap = resource;
                    initBitmap(resource);
                }

                @Override
                public void onLoadCleared(@Nullable Drawable placeholder) {
                    LogUtils.e(TAG, "onLoadCleared =================================================");
                    bitmap = null;
                    bitmapInfo = null;
                    postInvalidate();
                }
            });
        }
    }

    public void reset() {
        if (bitmap != null && data != null) {
            initBitmap(bitmap);
        }
    }

    public static void setCenterInside(boolean centerInside) {
        DiagnosisView.centerInside = centerInside;
    }

    private void onAngleChange() {
        if (isDisableDrawAngle) return;
        if (circlePoint != null && angles != null && angles.size() == 2) {
            Angle angle = angles.get(angles.size() - 1);
            Point point1 = angle.getPoints().get(2);
            Point point2 = angle.getPoints().get(3);
            float centerX = (point1.getX() + point2.getX()) / 2.0f;
            float centerY = (point1.getY() + point2.getY()) / 2.0f;

            List<Angle> list = new ArrayList<>();
            Angle angle1 = new Angle();
            angle1.getPoints().add(new Point(centerX, centerY));
            angle1.getPoints().add(new Point(circlePoint.getX(), circlePoint.getY()));
            angle1.getPoints().add(new Point(circlePoint.getX(), circlePoint.getY()));
            angle1.getPoints().add(new Point(circlePoint.getX(), circlePoint.getY() - dashLength));
            angle1.calculateAngle();
            list.add(angle1);

            Angle angle2 = new Angle();
            angle2.getPoints().add(new Point(centerX, centerY));
            angle2.getPoints().add(new Point(circlePoint.getX(), circlePoint.getY()));
            angle2.getPoints().add(new Point(centerX, centerY));
            angle2.getPoints().add(Utils.calculateCenterPoint(point1, point2, dashLength));
            angle2.calculateAngle();
            list.add(angle2);
            circlePoint.setAngles(list);
        } else if (circlePoint != null) {
            circlePoint.setAngles(null);
        }

        if (onAngleListener != null) {
            onAngleListener.onAngleChange(this, angles, circlePoint);
        }
    }

    public void setOnAngleListener(OnAngleListener onAngleListener) {
        this.onAngleListener = onAngleListener;
    }

    public void setEditing(boolean editing) {
        this.editing = editing;
        postInvalidate();
    }

    public ArrayList<Float> addCustomAngle(float x, float y) {
        ArrayList<Float> point = new ArrayList<>();
        point.add(x);
        point.add(y);
        return point;
    }

    public boolean addAngle(ImageInfo item, boolean isAngle) {
        if (angles == null) {
            ToastUtils.getInstance().show(R.string.diagnosis_view_init_fail);
            return false;
        }
        if (isAngle) {
            if (!item.isShowCondition() && angles.size() > 1) {
                ToastUtils.getInstance().show(R.string.add_angle_max_limit);
                return false;
            }
            List<List<Float>> customData = new ArrayList<>();
            customData.add(addCustomAngle(bitmap.getWidth() / 4.0f, bitmap.getHeight() / 2.0f - 20));
            customData.add(addCustomAngle(bitmap.getWidth() / 4.0f * 3, bitmap.getHeight() / 2.0f - 20));
            customData.add(addCustomAngle(bitmap.getWidth() / 4.0f, bitmap.getHeight() / 2.0f + 20));
            customData.add(addCustomAngle(bitmap.getWidth() / 4.0f * 3, bitmap.getHeight() / 2.0f + 20));
            angles.addAll(pointToAngles(customData, true));
            angles.get(angles.size() - 1).setTemp(true);
            onAngleChange();
            refreshDraw();
        } else if (circlePoint == null) {
            ArrayList<Float> circle = new ArrayList<>();
            circle.add(bitmap.getWidth() / 2.0f);
            circle.add(bitmap.getHeight() / 2.0f);
            circlePoint = new Point(circle, bitmapInfo.getOriginScale(), customColor, customColor, null);
            circlePoint.setTemp(true);
            onAngleChange();
            refreshDraw();
        } else {
            ToastUtils.getInstance().show(R.string.add_circle_max_limit);
            return false;
        }
        return true;
    }

    public interface OnAngleListener {
        void onAngleChange(DiagnosisView diagnosisView, List<Angle> angles, Point circlePoint);
    }
}
